#ifndef DSPSIMULATOR_DSPINSTFETCHER_H
#define DSPSIMULATOR_DSPINSTFETCHER_H

#include <simulator/instFetcher.h>
#include <dspSimulator/targetMachine/dspInstInfo.h>

/**
 * DspInstFetcher类用于从targetMachine中取出指令指针寄存器指向的一条指令数据
 */
class DspInstFetcher : public InstFetcher {
private:
    std::vector<u8> m_fetchPacket;              // 一次取指取出的指令包bit
    bool m_isStandard;                          // 取指包是否为Standard C6000 Fetch Packet
    u32 m_beginAddr;                            // 当前取指包的起始内存地址
    std::bitset<32> m_headWord;                 // 当前取指包的headWord
    bool m_enableMemory;                        // 标志位，用于标识是否锁存

    /**
     * 更新取指包缓存，新的取指包的首地址由参数指定
     * @param beginAddress 新的取指包的首地址
     */
    void updateFetchPacket(u32 beginAddress);

    /**
    * 从指令包偏移为offset处读取size个字节
    * @param size 字节数
    * @param offset 指令在取指包中的偏移量
    * @return
    */
    std::vector<u8> readBytesFromFetchPacket(u32 offset, u32 size);

    /**
     * 获取指令包的指令布局信息
     * @return 包含指令布局信息的7个bit
     */
    std::bitset<7> getLayoutWord() const;

    /**
     * 从指定的地址处取出一条指令的信息
     * @param address
     * @return
     */
    std::shared_ptr<InstInfo> fetchOneInstruction(u32 address);

    /**
     * 0 Loads are nonprotected (NOPs must be explicit).
     * 1 Loads are protected (4 NOP cycles added after every LD instruction)
     * @return
     */
    bool getPROT() const;

    /**
     * 0 Compact instructions do not saturate.
     * 1 Compact instructions saturate.
     * @return
     */

    bool getSAT() const;

    /**
      *  0 Instructions use low register set for m_data source and destination.
      *  1 Instructions use high register set for m_data source and destination
      * @return
      */
    bool getRS() const;


    /**
     *  0 Compact instructions in the S unit are not decoded as branches
     *  1 Compact Instructions in the S unit are decoded as branches.
     * @return
     */
    bool getBR() const;

    /**
     * Defines primary and secondary m_data size
     * @return
     */
    std::bitset<3> getDSZ() const;

    /**
     * 判断当前取指包是否为standard取指包
     * @return
     */
    bool isStandard() const;

    /**
     * 获取当前地址处的Compact指令的p位
     * @param address Compact指令的地址
     * @return
     */
    bool isParallelCompactInst(u32 address) const;

public:
    explicit DspInstFetcher(std::shared_ptr<TargetMachine> targetMachine) :
            InstFetcher(targetMachine), m_isStandard(true), m_beginAddr(0), m_enableMemory(true) {};

    ~DspInstFetcher() override = default;

    /**
     * 从targetMachine中取出指令指针寄存器指向的一条指令数据
     * @return
     */
    std::shared_ptr<InstInfo> fetchOneInstruction() override;

    /**
     * 设置取指器的状态，即是否锁存。如果锁存，无法从内存中取出指令
     * @param enableMemory   如果为false，表示锁存，无法从内存中取出指令
     */
    void setFetchState(bool enableMemory);
};

#endif //DSPSIMULATOR_DSPINSTFETCHER_H
